<?php


/**
 * 用户注册.
 *
 * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
 * @copyright ©2003-2103 phpwind.com
 * @license http://www.phpwind.com
 *
 * @version $Id: PwRegisterService.php 25182 2013-03-06 07:54:07Z long.shi $
 */
class PwRegisterService extends PwBaseHookService
{
    public $config = null;
    private $activeCodeValidTime = 3; //激活码有效期，单位小时
    /* @var $userDm PwUserInfoDm */
    private $userDm = null;
    /* @var $isOpenInvite int 是否开启邀请注册，开启时该值为1 */
    public $isOpenInvite = 0;
    /* @var $isOpenMobileCheck int 是否开启手机验证，开启时该值为1 */
    public $isOpenMobileCheck = 0;

    public function __construct()
    {
        parent::__construct();
        $this->config = Wekit::C('register');
        $this->isOpenInvite = (2 == $this->config['type'] ? 1 : 0);
        $this->isOpenMobileCheck = (1 == $this->config['active.phone'] ? 1 : 0);
    }

    /**
     * 检查是否设置同一IP设置一段时间内不能注册.
     *
     * @param string $ip 待检查的IP
     *
     * @return true|PwError
     */
    public function checkIp($ip)
    {
        if (!($ipSpace = abs($this->config['security.ip']))) {
            return true;
        }
        $space = $ipSpace * 3600;
        /* @var $registerDs PwUserRegisterIp */
        $registerDs = Wekit::load('user.PwUserRegisterIp');
        $data = $registerDs->getRecodeByIp($ip);
        if (!$data || Pw::getTime() - $data['last_regdate'] > $space) {
            return true;
        }

        return new PwError('USER:register.error.security.ip', array('{ipSpace}' => $ipSpace));
    }

    /**
     * 设置用户信息.
     *
     * @param PwUserInfoDm $userForm
     */
    public function setUserDm(PwUserInfoDm $userDm)
    {
        $this->userDm = $this->filterUserDm($userDm);
    }

    /**
     * 返回用户信息的DM.
     *
     * @return PwUserInfoDm
     */
    public function getUserDm()
    {
        return $this->userDm;
    }

    /**
     * 用户注册信息.
     *
     * @return bool|int
     */
    public function register()
    {
        if (!$this->userDm) {
            return new PwError('USER：illegal.request');
        }
        if (($result = $this->checkIp($this->userDm->getField('regip'))) instanceof PwError) {
            return $result;
        }
        //[c_register]:调用插件中用户注册操作的前置方法beforeRegister
        if (($result = $this->runWithVerified('beforeRegister', $this->userDm)) instanceof PwError) {
            return $result;
        }
        if (($uid = $this->_getUserDs()->addUser($this->userDm)) instanceof PwError) {
            return $uid;
        }
        //记录一下ip次数
        $this->_recordIpLimit($uid);
        //
        $this->userDm->setUid($uid);

        return $this->afterRegister($this->userDm);
    }

    /**
     * 同步用户数据.
     *
     * 如果本地有用户数据
     * 如果本地没有用户数据，则将用户数据从windid同步过来
     *
     * @param int $uid
     *
     * @return array
     */
    public function sysUser($uid)
    {
        $info = $this->_getUserDs()->getUserByUid($uid, PwUser::FETCH_MAIN);
        if (!$info) {
            //从windid这边将数据同步到论坛
            if (!$this->_getUserDs()->activeUser($uid)) {
                return false;
            }
            //更新用户信息
            $pwUserInfoDm = new PwUserInfoDm($uid);
            $_userinfo = $this->_getUserDs()->getUserByUid($uid, PwUser::FETCH_MAIN | PwUser::FETCH_DATA);
            $this->_getUserDs()->editUser($this->filterUserDm($pwUserInfoDm, $_userinfo));
            Wekit::load('user.srv.PwUserService')->restoreDefualtAvatar($info['uid']);

            $pwUserInfoDm->setUsername($_userinfo['username']);
            $pwUserInfoDm->setEmail($_userinfo['email']);
            $pwUserInfoDm->setRegip(Wind::getComponent('request')->getClientIp());
            $info = $this->afterRegister($pwUserInfoDm);
            $this->sendEmailActive($_userinfo['username'], $_userinfo['email']);
        }

        return $info;
    }

    /**
     * 需要发送新用户激活邮件.
     *
     * @param string $username 用户名
     * @param string $email    用户邮件
     * @param string $statu    激活标志
     * @param int    $uid      用户ID
     *
     * @return bool
     */
    public function sendEmailActive($username, $email, $statu = '', $uid = 0)
    {
        if (!$this->config['active.mail']) {
            return true;
        }
        if ($uid == 0 || !$statu) {
            $info = $this->_getUserDs()->getUserByName($username, PwUser::FETCH_MAIN);
            if ($info['email'] != $email) {
                return new PwError('USER:illegal.request');
            }
            $uid = $info['uid'];
            $statu = self::createRegistIdentify($uid, $info['password']);
        }
        if (!Wind::getComponent('router')->getRoute('pw')) {
            Wind::getComponent('router')->addRoute('pw', new PwRoute('bbs'));
        }

        $code = substr(md5(Pw::getTime()), mt_rand(1, 8), 8);
        $url = WindUrlHelper::createUrl('u/register/activeEmail', array('code' => $code, '_statu' => $statu), '', 'pw');
        list($title, $content) = $this->_buildTitleAndContent('active.mail.title', 'active.mail.content', $username, $url);
        /* @var $activeCodeDs PwUserActiveCode */
        $activeCodeDs = Wekit::load('user.PwUserActiveCode');
        $activeCodeDs->addActiveCode($uid, $email, $code, Pw::getTime());
        $mail = new PwMail();
        $mail->sendMail($email, $title, $content);

        return true;
    }

    /**
     * 检查是否已经发送了激活邮箱.
     *
     * @param int    $uid   用户ID
     * @param string $email 用户邮箱
     *
     * @return bool
     */
    public function checkIfActiveEmailSend($uid, $email)
    {
        /* @var $activeCodeDs PwUserActiveCode */
        $activeCodeDs = Wekit::load('user.PwUserActiveCode');
        $info = $activeCodeDs->getInfoByUid($uid);
        if (!$info || $info['email'] != $email || $info['active_time'] > 0) {
            return false;
        }
        $validTime = $this->activeCodeValidTime * 3600;
        //过期了
        if (($info['send_time'] + $validTime) < Pw::getTime()) {
            return false;
        }

        return true;
    }

    /**
     * 激活email.
     *
     * @param int    $uid   用户ID
     * @param string $email 用户Email
     * @param string $code  激活码
     *
     * @return bool
     */
    public function activeEmail($uid, $email, $code)
    {
        /* @var $activeCodeDs PwUserActiveCode */
        $activeCodeDs = Wekit::load('user.PwUserActiveCode');
        $info = $activeCodeDs->getInfoByUid($uid);
        if (!$info || $info['email'] != $email || $info['code'] != $code) {
            return new PwError('USER:illegal.request');
        }
        if ($info['active_time'] > 0) {
            return new PwError('USER:active.email.dumplicate');
        }
        $validTime = $this->activeCodeValidTime * 3600;
        if (($info['send_time'] + $validTime) < Pw::getTime()) {
            return new PwError('USER:active.email.overtime');
        }
        $activeCodeDs->activeCode($uid, Pw::getTime());

        $info = $this->_getUserDs()->getUserByUid($uid, PwUser::FETCH_MAIN);
        if (Pw::getstatus($info['status'], PwUser::STATUS_UNACTIVE)) {
            $userDm = new PwUserInfoDm($info['uid']);
            $userDm->setUnactive(false);
            (!Pw::getstatus($info['status'], PwUser::STATUS_UNCHECK)) && $userDm->setGroupid(0);
            $this->_getUserDs()->editUser($userDm, PwUser::FETCH_MAIN);
        }
        /* @var $registerCheckDs PwUserRegisterCheck */
        $registerCheckDs = Wekit::load('user.PwUserRegisterCheck');
        $registerCheckDs->activeUser($uid);

        return true;
    }

    /**
     * 发送欢迎信息.
     *
     * @param int    $uid      用户ID
     * @param string $username 用户名
     * @param string $email    邮箱
     *
     * @return bool
     */
    public function sendWelcomeMsg($uid, $username, $email)
    {
        list($title, $content) = $this->_buildTitleAndContent('welcome.title', 'welcome.content', $username);
        if (in_array(1, $this->config['welcome.type'])) {
            /* @var $notice PwNoticeService */
            $notice = Wekit::load('message.srv.PwNoticeService');
            $notice->sendDefaultNotice($uid, $content, $title);
        }

        /*如果含有激活邮件则发送到*/
        if (!in_array(2, $this->config['welcome.type'])) {
            return true;
        }
        //如果是邮件激活开启，则不需要发送欢迎邮件
        if ($this->config['active.mail'] == 1) {
            return true;
        }
        $mail = new PwMail();
        $mail->sendMail($email, $title, $content);

        return true;
    }

    /**
     * 构造用户标志.
     *
     * @param int    $uid 用户ID
     * @param string $pwd 用户密码
     *
     * @return string
     */
    public static function createRegistIdentify($uid, $pwd)
    {
        $code = Pw::encrypt($uid."\t".Pw::getPwdCode($pwd));

        return rawurlencode($code);
    }

    /**
     * 检查用户标志.
     *
     * @param string $identify
     *
     * @return array array($uid, $password);
     */
    public static function parserRegistIdentify($identify)
    {
        return explode("\t", Pw::decrypt(rawurldecode($identify)));
    }

    /**
     *  完成注册的后期执行.
     *
     * @param PwUserInfoDm $userDm
     *
     * @return array
     */
    protected function afterRegister(PwUserInfoDm $userDm)
    {
        //Wekit::load('user.srv.PwUserService')->restoreDefualtAvatar($uid); windid处理
        //获得注册积分
        /* @var $creditBo PwCreditBo */
        $creditBo = PwCreditBo::getInstance();
        $creditBo->operate('register', new PwUserBo($userDm->uid));

        $this->updateRegisterIp($userDm->getField('regip'), Pw::getTime());
        $this->updateRegisterCheck($userDm->uid);
        $this->sendWelcomeMsg($userDm->uid, $userDm->getField('username'), $userDm->getField('email'));

        //[c_register]:调用插件中用户注册操作的后置方法afterRegister
        if (($result = $this->runWithVerified('afterRegister', $userDm)) instanceof PwError) {
            return $result;
        }

        return $this->_getUserDs()->getUserByUid($userDm->uid, PwUser::FETCH_MAIN);
    }

    /**
     * 过滤用户DM同时设置用户的相关信息.
     *
     * @param PwUserInfoDm $userDm
     * @param array        $hasCredit
     *
     * @return PwUserInfoDm
     */
    protected function filterUserDm(PwUserInfoDm $userDm, $hasCredit = array())
    {
        //如果开启邮箱激活，则设置该状态为0，否则设置该状态为1
        $_uncheckGid = false;
        if ($this->config['active.mail']) {
            $userDm->setUnactive(true);
            $_uncheckGid = true;
        }
        //如果开启审核，则设置该状态为0，否则设置该状态为1
        if ($this->config['active.check']) {
            $userDm->setUncheck(true);
            $_uncheckGid = true;
        }
        //【用户注册】未验证用户组
        if ($_uncheckGid) {
            $userDm->setGroupid(7);
            $userDm->setGroups(array());
        }
        $_credit = $this->_getRegisterAddCredit($hasCredit);
        //【用户注册】计算memberid
        /* @var $groupService PwUserGroupsService */
        $groupService = Wekit::load('usergroup.srv.PwUserGroupsService');
        $credit = $groupService->calculateCredit(Wekit::C('site', 'upgradestrategy'), $_credit);
        $memberid = $groupService->calculateLevel($credit);
        $userDm->setMemberid($memberid);

        return $userDm;
    }

    /**
     * 获取注册可以添加的积分.
     *
     * @param array $_credit 已有的积分
     *
     * @return array
     */
    private function _getRegisterAddCredit($_credit = array())
    {
        //【用户注册】注册成功初始积分---积分策略中获取
        /* @var $creditBo PwCreditBo */
        $creditBo = PwCreditBo::getInstance();
        $creditStrategy = $creditBo->getStrategy('register');
        !$creditStrategy['credit'] && $creditStrategy['credit'] = array();
        foreach ($creditStrategy['credit'] as $id => $_v) {
            $_id = 'credit'.$id;
            if (isset($_credit[$_id])) {
                $_credit[$_id] += $_v;
            } else {
                $_credit[$_id] = $_v;
            }
        }

        return $_credit;
    }

    /**
     * 获得信息的标题和内容.
     *
     * @param string $titleKey   标题key
     * @param string $contentKey 内容key
     * @param string $username   用户名
     * @param string $url        链接地址
     *
     * @return array
     */
    private function _buildTitleAndContent($titleKey, $contentKey, $username, $url = '')
    {
        $search = array('{username}', '{sitename}');
        $replace = array($username, Wekit::C('site', 'info.name'));
        $title = str_replace($search, $replace, $this->config[$titleKey]);
        $search[] = '{time}';
        $search[] = '{url}';
        $replace[] = Pw::time2str(Pw::getTime(), 'Y-m-d H:i:s');
        $replace[] = $url ? sprintf('<a href="%s">%s</a>', $url, $url) : '';
        $content = str_replace($search, $replace, $this->config[$contentKey]);

        return array($title, $content);
    }

    /**
     * 更新注册IP.
     *
     * @param string $ip   注册的IP
     * @param int    $time 注册时间
     *
     * @return bool
     */
    private function updateRegisterIp($ip, $time)
    {
        if (!$this->config['security.ip']) {
            return true;
        }
        /* @var $registerDa PwUserRegisterIp */
        $registerDs = Wekit::load('user.PwUserRegisterIp');

        return $registerDs->updateRecodeByIp($ip, $time);
    }

    /**
     * 更新用户注册相关的审核/激活表.
     *
     * @param int $uid
     *
     * @return bool
     */
    private function updateRegisterCheck($uid)
    {
        //添加到注册审核表中
        $_ifactive = $this->config['active.mail'] ? 0 : 1;
        $_ifcheck = $this->config['active.check'] ? 0 : 1;
        /* @var $registerCheckDs PwUserRegisterCheck */
        $registerCheckDs = Wekit::load('user.PwUserRegisterCheck');
        $registerCheckDs->addInfo($uid, $_ifcheck, $_ifactive);

        return true;
    }

    /**
     * 获得用户DS.
     *
     * @return PwUser
     */
    private function _getUserDs()
    {
        return Wekit::load('user.PwUser');
    }

    /* (non-PHPdoc)
     * @see PwBaseHookService::_getInterfaceName()
     */
    protected function _getInterfaceName()
    {
        return 'PwRegisterDoBase';
    }

    private function _recordIpLimit()
    {
        $pwdBp = new PwTryPwdBp();
        $pwdBp->allowTryAgain($uid, Wind::getComponent('request')->getClientIp(), true);
    }
}
